package top.ljlgithub.api.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName
 * @Description TODO
 * @Author L1470
 * @Date 2021/5/16 20:14
 * @Version 1.0
 **/
@Component
public final class RedisUtil {

    public RedisUtil() {
    }

    public RedisUtil(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public RedisTemplate<String, Object> getRedisTemplate() {
        return redisTemplate;
    }

    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    //========================common=============================

    /**
     * @Author ljl
     * @Description 获取redis连接对象
     * @Date 22:12
     * @Param
     * @return
     **/
    public RedisConnection getRedisConnection(){
        try {
            RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
            return connection;
        }catch (Exception e){
            return null;
        }
    }

    /**
     * @Author ljl
     * @Description 清空所有数据
     * @Date 22:15
     * @Param
     * @return
     **/
    public boolean flushAll(){
        try {
            getRedisConnection().flushAll();
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * @Author ljl
     * @Description 清空当前数据库的数据
     * @Date 22:17
     * @Param
     * @return
     **/
    public boolean flushDb(){
        try {
            getRedisConnection().flushDb();
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * @Author ljl
     * @Description 判断是否连接成功
     * @Date 22:22
     * @Param []
     * @return boolean
     **/
    public boolean connect(){
        try {
            String ping = getRedisConnection().ping();
            if ("PONG".equals(ping)){
                return true;
            }
            return false;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }


    /**
     * @Author ljl
     * @Description 指定缓存失效时间
     * @Date 20:17 
     * @Param key 键
     * @return time 时间(秒)
     **/
    public boolean expire(String key,long time){
        try {
            if (time > 0){
                redisTemplate.expire(key,time, TimeUnit.SECONDS);
            }
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }
    
    /**
     * @Author ljl
     * @Description 根据key获取过期时间
     * @Date 20:20 
     * @Param key 键不能为null
     * @return 时间（秒）返回0表示永久有效
     *
     **/
    public long getExpire(String key){
        return redisTemplate.getExpire(key,TimeUnit.SECONDS);
    }

    /**
     * @Author ljl
     * @Description 判断key是否存在
     * @Date 20:22
     * @Param key 键
     * @return true 存在 false 不存在
     **/
    public boolean hasKey(String key){
        try{
            return redisTemplate.hasKey(key);
        }catch (Exception e){
            e.printStackTrace();;
            return false;
        }
    }

    /**
     * @Author ljl
     * @Description 删除缓存
     * @Date 20:23
     * @Param key 可以传一个或多个
     * @return
     **/
    public void del(String... key){
        if (key != null && key.length > 0){
            if (key.length == 1){
                redisTemplate.delete(key[0]);
            }else {
                redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
            }
        }
    }

    //==================================String========================

    /**
     * @Author ljl
     * @Description 普通缓存的获取
     * @Date 20:26 key 键
     * @Param 值
     * @return
     **/
    public Object get(String key){
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     * @Author ljl
     * @Description 普通缓存的放入
     * @Date 20:28
     * @Param key
     * @return value
     **/
    public boolean set(String key,Object value){
        try {
            redisTemplate.opsForValue().set(key,value);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * @Author ljl
     * @Description 普通缓存放入并设置时间
     * @Date 20:30 
     * @Param key，value,time
     * @return true：成功false：失败
     **/
    public boolean set(String key,Object value,long time){
        try {
            if (time > 0){
                redisTemplate.opsForValue().set(key,value,time,TimeUnit.SECONDS);
            }else {
                set(key,value);
            }
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }
    
    /**
     * @Author ljl
     * @Description 递增
     * @Date 20:33
     * @Param key，delta
     * @return 
     **/
    public long incr(String key,long delta){
        if (delta < 0){
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key,delta);
    }

    /**
     * @Author ljl
     * @Description 递减
     * @Date 20:34
     * @Param key，delta
     * @return
     **/
    public long decr(String key,long delta){
        if (delta < 0){
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key,-delta);
    }

    //===========================map============================

    /**
     * @Author ljl
     * @Description HashGet
     * @Date 21:07
     * @Param key，item 不能为null
     * @return
     **/
    public Object hget(String key,String item){
        return redisTemplate.opsForHash().get(key,item);
    }

    /**
     * @Author ljl
     * @Description 获取hashKey对应的所有的键值
     * @Date 21:09
     * @Param key
     * @return 对应的多个键值
     **/
    public Map<Object,Object> hmget(String key){
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * @Author ljl
     * @Description HashSet
     * @Date 21:11
     * @Param key,map对应多个键值
     * @return
     **/
    public boolean hmset(String key,Map<String,Object> map){
        try{
            redisTemplate.opsForHash().putAll(key,map);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * @Author ljl
     * @Description 添加set的同时设置时间
     * @Date 21:18
     * @Param key，map，time
     * @return true：success false：fail
     **/
    public boolean hmset(String key,Map<String,Object> map,long time){
        try {
            redisTemplate.opsForHash().putAll(key,map);
            if (time > 0){
                expire(key,time);
            }
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * @Author ljl
     * @Description 向一张hash表中放入数据，如果不存在就创建
     * @Date 21:20
     * @Param key，item，value
     * @return
     **/
    public boolean hset(String key,String item,Object value){
        try {
            redisTemplate.opsForHash().put(key,item,value);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * @Author ljl
     * @Description 添加hash元素时设置时间
     * @Date 21:23
     * @Param key,item,value,time
     * @return
     **/
    public boolean hset(String key,String item,Object value,long time){
        try {
            redisTemplate.opsForHash().put(key,item,value);
            if (time > 0){
                expire(key,time);
            }
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * @Author ljl
     * @Description 删除hash表中的值
     * @Date 21:25
     * @Param key 不能为null ，item 可以多个，不能为null
     * @return
     **/
    public Long hdel(String key,Object... item){
        return redisTemplate.opsForHash().delete(key, item);
    }
    
    /**
     * @Author ljl
     * @Description 判断hash表中是否有该项的值
     * @Date 21:28 
     * @Param key ，item
     * @return 
     **/
    public boolean hHasKey(String key,String item){
        return redisTemplate.opsForHash().hasKey(key,item);
    }
    
    /**
     * @Author ljl
     * @Description hash递增，如果不存在，就创建一个，并把新增的值返回
     * @Date 21:30 
     * @Param key ,item,by
     * @return 
     **/
    public double hincr(String key,String item,double by){
        return redisTemplate.opsForHash().increment(key,item,by);
    }

    /**
     * @Author ljl
     * @Description hash递减
     * @Date 21:31
     * @Param key，item，by
     * @return
     **/
    public double hdecr(String key,String item,double by){
        return redisTemplate.opsForHash().increment(key,item,-by);
    }

    /**
     * @Author ljl
     * @Description 返回hash的元素的个数
     * @Date 6:43
     * @Param
     * @return
     **/
    public int hGetHashSize(String key){
        return redisTemplate.opsForHash().size(key).intValue();
    }

    /**
     * @Author ljl
     * @Description 获取hash所有的key
     * @Date 6:47
     * @Param
     * @return
     **/
    public Set<Object> hKeys(String key){
        return redisTemplate.opsForHash().keys(key);
    }

    /**
     * @Author ljl
     * @Description 获取所有vals
     * @Date 7:07
     * @Param
     * @return
     **/
    public List hValues(String key){
        return redisTemplate.opsForHash().values(key);
    }
    
    //====================set====================
    
    /**
     * @Author ljl
     * @Description 根据key获取Set中所有的值
     * @Date 21:32
     * @Param key
     * @return
     **/
    public Set<Object> sGet(String key){
        try {
            return redisTemplate.opsForSet().members(key);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
    
    /**
     * @Author ljl
     * @Description 根据value从一个set中查询,是否存在
     * @Date 21:35 
     * @Param key，value
     * @return 
     **/
    public boolean sHashKey(String key,Object value){
        try {
            return redisTemplate.opsForSet().isMember(key,value);
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * @Author ljl
     * @Description 将数据放入set缓存
     * @Date 21:37
     * @Param key,values可以为多个
     * @return
     **/
    public long sSet(String key,Object... values){
        try {
            return redisTemplate.opsForSet().add(key,values);
        }catch (Exception e){
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * @Author ljl
     * @Description 将数据放入set中，并设置过期时间
     * @Date 21:39
     * @Param key,values,time
     * @return
     **/
    public long sSetAndTime(String key ,long time,Object... values){
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0) {
                expire(key, time);
            }
            return count;
        }catch (Exception e){
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * @Author ljl
     * @Description 获取set缓存的长度
     * @Date 21:43
     * @Param key
     * @return
     **/
    public long sGetSetSize(String key){
        try {
            return redisTemplate.opsForSet().size(key);
        }catch (Exception e){
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * @Author ljl
     * @Description 移除值为value
     * @Date 21:44
     * @Param key
     * @return values
     **/
    public long setRemove(String key,Object... values){
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        }catch (Exception e){
            e.printStackTrace();
            return 0;
        }
    }

    //===============list===============

    /**
     * @Author ljl
     * @Description 获取list缓存的长度
     * @Date 21:46
     * @Param key
     * @return
     **/
    public long lGetListSize(String key){
        try {
            return redisTemplate.opsForList().size(key);
        }catch (Exception e){
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * @Author ljl
     * @Description 通过索引获取list中的值
     * @Date 21:48
     * @Param key 键，index
     * @return
     **/
    public Object lGetIndex(String key,long index){
        try {
            return redisTemplate.opsForList().index(key,index);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @Author ljl
     * @Description 添加值
     * @Date 21:50
     * @Param
     * @return
     **/
    public boolean lSet(String key,Object value){
        try {
            redisTemplate.opsForList().rightPush(key,value);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * @Author ljl
     * @Description list中添加值，并设置时间
     * @Date 21:52
     * @Param
     * @return
     **/
    public boolean lSet(String key,Object value,long time){
        try{
            redisTemplate.opsForList().rightPush(key,value);
            if (time > 0){
                expire(key,time);
            }
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * @Author ljl
     * @Description 根据索引修改list中的某条数据
     * @Date 21:55
     * @Param
     * @return
     **/
    public boolean lUpdateIndex(String key,long index,Object value){
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * @Author ljl
     * @Description 移除n个值为value
     * @Date 21:56
     * @Param
     * @return
     **/
    public long lRemove(String key,long count,Object value){
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        }catch (Exception e){
            e.printStackTrace();
            return 0;
        }
    }


}
